#include "TcpServer.h"
#include "log.h"
// #include "TcpServer.h"
// #include "log.h"
#include "TcpConnection.h"

// #include <strings.h>
// #include <functional>
static EventLoop *CheckLoopNotNull(EventLoop *loop)
{
    if (loop == nullptr)
    {
        LOG_FATAL("%s:%s:%d mainloop is null\n", __FILE__, __FUNCTION__, __LINE__);
    }
    return loop;
}

TcpServer::TcpServer(EventLoop *loop,
                     const InetAddress &listenAddr, const std::string &nameArg, Option option)
    : loop_(CheckLoopNotNull(loop)), IpPort_(listenAddr.toIpPort()), name_(nameArg), acceptor_(new Acceptor(loop_, listenAddr, option == KReusePort)), threadPool_(new EventLoopThreadPool(loop_, name_)), ConnectionCallback_(), MessageCallback_(), nextConnId_(1),started_(0)
{
    // 当有新用户连接时会执行newCOnnection执行回调
    acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
};
TcpServer::~TcpServer()
{

    for (auto &item : connections_)
    {
        TcpConnectionPtr conn(item.second); // 这个局部的强智能指针对象生命周期结束后,自动释放资源
        item.second.reset();
        //销毁链接
        conn->getLoop()->runInLoop(std::bind(&TcpConnection::connectionDestoryed, conn)); 
    }
};
void TcpServer::setThreadNum(int numThreads)
{
    threadPool_->setThreadNum(numThreads);
}

void TcpServer::start()
{
    if (started_++ == 0)
    {                                            // 防止多次调用
        threadPool_->start(threadInitCallback_); // 启用loop线程池
        loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_.get()));
    }
};

// 有新的客户端链接后执行这个操作
void TcpServer::newConnection(int sockfd, const InetAddress  &peerAddr)
{
    // 轮询算法,来选择一个sublloop来管理channel
    EventLoop *ioLoop = threadPool_->getNextloop();
    char buf[64] = {0};
    snprintf(buf, sizeof buf, "%s#%d", IpPort_.c_str(), nextConnId_++);
    ++nextConnId_;
    std::string connName = name_ + buf;

    LOG_INFO("TcpServer::newConnection [%s] - new connection [%s] from %s\n", name_.c_str(), connName.c_str(), peerAddr.toIpPort().c_str());
    // 通过SOCKET获取其本地的ip地址和端口信息
    sockaddr_in local;
    ::bzero(&local, sizeof local);
    socklen_t addrlen = sizeof local;
    if (::getsockname(sockfd, (sockaddr *)&local, &addrlen) < 0)
    {
        LOG_ERROR("sockets::getLocalAddr");
    }
    InetAddress localAddr(local);

    // 根据创建成功的socket,船舰TcpConnection连接对象
    TcpConnectionPtr conn(new TcpConnection(ioLoop, connName, sockfd, localAddr, peerAddr));

    connections_[connName] = conn;
    // 给新连接绑定相应的回调
    conn->setConnectionCallback(ConnectionCallback_);
    conn->setMessagecallback(MessageCallback_);
    conn->setWriteComplateCallback(WriteCompleteCallback_);
    // 设置了如何关闭连接的回调
    conn->setCloseCallback(std::bind(&TcpServer::removeConnection, this, std::placeholders::_1));
    // 直接调用Tcp链接的创建方法

    ioLoop->runInLoop(std::bind(&TcpConnection::connectionEstablished, conn));
};
void TcpServer::removeConnection(const TcpConnectionPtr &conn)
{
    loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn));
};
void TcpServer::removeConnectionInLoop(const TcpConnectionPtr &conn)
{
    LOG_INFO("TcpServer::removeConnection [%s] - connection %s\n", name_.c_str(), conn->name().c_str());

    connections_.erase(conn->name());

    EventLoop *ioLoop = conn->getLoop();
    ioLoop->queueInLoop(std::bind(&TcpConnection::connectionDestoryed, conn));
};